package progetto1.csm.implementation;

import java.util.LinkedList;
import java.util.Queue;

import progetto1.csm.core.SystemElement;
import progetto1.csm.core.actor.Client;
import progetto1.csm.core.actor.Element;
import progetto1.csm.core.actor.Watcher;
import sde.actor.Message;
import sde.actor.distribution.Distribution;

public class Station extends Element {
	
	private static class Init extends Message {
		private Element nextElement;
		private Distribution distribution;

		private Init(Element nextElement, Distribution distribution) {
			super();
			this.nextElement = nextElement;
			this.distribution = distribution;
		}
	}

	private static class Served extends Message {
		private Client client;

		private Served(Client client) {
			super();
			this.client = client;
		}
	}
	
	private final byte CREATED = 0, FREE = 1, BUSY = 2;//stati
	private Element nextElement;
	private Distribution distribution;
	private Arrival arrival = null;//arrival del cliente attualmente in servizio
	private Served serv = new Served(null);//messaggio che mi autoinvio
	private Queue<Arrival> waitingQueue = new LinkedList<Arrival>();

	protected Station(Watcher watcher, SystemElement element) {
		super(watcher, element);
	}
	
	protected void init(Distribution distribution, Element nextElement){
		this.send(new Init(nextElement,distribution));
		waitingQueue.clear();
		arrival = null;
		become(CREATED);
	}
	
	private double nextSample(){
		return now()+distribution.nextSample();
	}

	@Override
	public void handler(Message m) {
		switch (currentStatus()) {
		case CREATED:
			if(m instanceof Init){
				Init i = (Init) m;
				this.distribution=i.distribution;
				this.nextElement=i.nextElement;
				become(FREE);
			}
			break;
		case FREE:
			if(m instanceof Arrival){
				arrival = (Arrival) m;
				enter(arrival.getClient());//segnalo al watcher
				serv.client = arrival.getClient();
				send(serv, nextSample());
				become(BUSY);
			}
			break;
		case BUSY:
			if(m instanceof Arrival){
				Arrival a = (Arrival) m;
				Client carr = a.getClient();
				enter(carr);
				waitingQueue.add(a);
			}
			else if(m instanceof Served){
				Served s = (Served) m;
				Client c = s.client;
				exit(c);
				nextElement.send(arrival);
				if(waitingQueue.isEmpty()){
					idle();
					become(FREE);
				}else{
					arrival = waitingQueue.poll();
					serv.client = arrival.getClient();
					send(serv, nextSample());
				}
			}
			break;
		default:
			assert false;
			break;
		}
	}
}
